﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Fizzler.Systems.HtmlAgilityPack;
using HtmlAgilityPack;
using System.Threading;
using System.IO;
using System.Configuration;

namespace AutoF3.ProblemRetrievers
{
    public abstract class ForumRetriever : ArtOfProblemSolvingRetriever
    {
        private Dictionary<string, string> _forumURLDict;
        private Dictionary<string, string> _cachedProblems = new Dictionary<string, string>();
        private object _problemDownloadLocker = new Object();
        private static List<Problem> _retList;

        protected List<string> CategoryList;
        protected string ForumURL;

        public override List<string> GetCategoryList() { return CategoryList; }

        public override List<Problem> RetrieveProblems(int numProblemsToRetrieve)
        {
            var dict = GetCachedURLs();
            _retList = new List<Problem>();
            int count = 0;

            var threads = new List<Thread>();
            foreach (var kvp in dict)
            {
                var temp = kvp;
                threads.Add(new Thread(() => ThreadSafeGetForumProblemFromURL(temp)));
                count++;
                if (count >= numProblemsToRetrieve)
                    break;
            }

            foreach (var t in threads)
                t.Start();
            foreach (var t in threads)
                t.Join();

            return _retList;
        }

        private void ThreadSafeGetForumProblemFromURL(KeyValuePair<string, string> kvp)
        {
            string name = kvp.Key;
            string url = kvp.Value;

            string h = GetCachedProblemHtml(url);

            var html = new HtmlDocument();
            html.LoadHtml(h);
            var document = html.DocumentNode;
            var postBodyNodes = document.QuerySelectorAll("div.postbody");

            bool isFirstPost = true;
            Problem prob = new Problem(name);

            foreach (var node in postBodyNodes)
            {
                string postText = GetPostTextInTeXFormat(node);
                postText = CleanUpPostHtml(postText);

                if (isFirstPost)
                {
                    prob.problemText = postText;// = new Problem(name, postText);
                    isFirstPost = false;
                }
                else
                    prob.AddPossibleSolution(postText);
            }

            lock (_problemDownloadLocker)
            {
                _retList.Add(prob);
            }
        }

        private Dictionary<string, string> RetrieveFromForumURL()
        {
            WebClient client = new WebClient();
            string h = client.DownloadString(ForumURL);

            int index = h.IndexOf("<td class=\"cat\" colspan=\"6\"><b class=\"gensmall\">Topics</b></td>");
            h = "<table class=\"tablebg\" width=\"100%\" style=\"margin-bottom:0\">" + h.Substring(index);

            var html = new HtmlDocument();
            html.LoadHtml(h);
            var document = html.DocumentNode;
            var nodes = document.QuerySelectorAll("table.tablebg td.row1 a");

            var urlDict = new Dictionary<string, string>();
            foreach (var node in nodes)
            {
                string url = node.GetAttributeValue("href", null);
                string linkName = node.InnerText;

                if (url.StartsWith("./viewtopic.php?") && !IsEntirelyNumeric(linkName))
                    urlDict[linkName] = "http://www.artofproblemsolving.com/Forum" + url.Substring(1).Replace("amp;", "");
            }

            return urlDict;
        }
        
        private bool IsEntirelyNumeric(string str)
        {
            foreach (char c in str)
                if ("0123456789".Contains(c))
                    return false;
            return true;
        }

        private Dictionary<string, string> GetCachedURLs()
        {
            if (_forumURLDict == null)
            {
                _forumURLDict = RetrieveFromForumURL();
                return _forumURLDict;
            }
            else
                return _forumURLDict;
        }

        private string GetCachedProblemHtml(string url)
        {
            string html;
            _cachedProblems.TryGetValue(url, out html);

            if (String.IsNullOrEmpty(html))
            {
                int hashValue = url.GetHashCode();
                uint hashValueUnsigned = (uint)int.MaxValue + (uint)hashValue;

                string fileDirectory = ConfigurationManager.AppSettings["CachedFilesDirectory"] + @"\";
                foreach (string str in GetCategoryList())
                    fileDirectory += str + @"\";

                string filePath = fileDirectory + hashValueUnsigned + ".txt";
                
                if (File.Exists(filePath))
                    html = File.ReadAllText(filePath);
                else
                {
                    if (!Directory.Exists(fileDirectory))
                        Directory.CreateDirectory(fileDirectory);

                    WebClient client = new WebClient();
                    html = client.DownloadString(url);
                    File.WriteAllText(filePath, html);
                }
                _cachedProblems[url] = html;
            }

            return html;
        }
    }
}
